﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using NetDon.OA.Data.CollectionClasses;
using NetDon.OA.Data.EntityClasses;
using NetDon.OA.Data.HelperClasses;
using NetDon.OA.Data.Linq;
using NetDon.OA.Interface;
using NetDon.OA.Interface.CRM;
using NetDon.OA.Interface.eLogistics;
using NetDon.Utilities;
using SD.LLBLGen.Pro.ORMSupportClasses;

namespace NetDon.OA.Business
{
    public partial class MachineAccountService : IMachineAccountService
    {
        public IEnumerable<MachineAccountData> SearchMachineAccountDataByCondition(MachineAccountSearchCriteria criteria)
        {
            var collectionPayment = new MachineAccountPaymentCollection();
            var collectionIncome = new MachineAccountIncomeCollection();
            if (criteria.PaymentOrIncome == MachineAccountType.Income)
            {
                collectionIncome.GetMulti(GetMachineAccountIncomePredicate(criteria));
            }
            else if (criteria.PaymentOrIncome == MachineAccountType.Payment)
            {
                collectionPayment.GetMulti(GetMachineAccountPaymentPredicate(criteria));
            }
            else
            {
                collectionIncome.GetMulti(GetMachineAccountIncomePredicate(criteria));
                collectionPayment.GetMulti(GetMachineAccountPaymentPredicate(criteria));
            }


            var result = (from customerInfo in collectionIncome orderby customerInfo.PaymentOrIncomeDate
                          select GetMachineAccountIncomeData(customerInfo) ).Union(
                              from customerInfo1 in collectionPayment
                              orderby customerInfo1.PaymentOrIncomeDate
                              select GetMachineAccountPaymentData(customerInfo1)
                );

            return result;
        }




        public bool AddMachineAccounts(MachineAccountData entity)
        {
            var trans = new Transaction(IsolationLevel.ReadCommitted, "AddMachineAccounts");
            return AddMachineAccounts(entity, trans);
        }


        public bool AddMachineAccounts(MachineAccountData entity, Transaction trans)
        {
            try
            {
                if (entity.PaymentOrIncome == MachineAccountType.Income)
                {
                    var machineAccountEntity = new MachineAccountIncomeEntity();
                    GetMachineAccountIncomeEntity(machineAccountEntity, entity);
                    machineAccountEntity.Id = entity.Id;
                    trans.Add(machineAccountEntity);
                    machineAccountEntity.Save();
                }
                else if (entity.PaymentOrIncome == MachineAccountType.Payment)
                {
                    var machineAccountEntity = new MachineAccountPaymentEntity();
                    GetMachineAccountPaymentEntity(machineAccountEntity, entity);
                    machineAccountEntity.Id = entity.Id;
                    trans.Add(machineAccountEntity);
                    machineAccountEntity.Save();
                    UpdateGoodsUnloadingCost(trans, entity);

                }

                trans.Commit();
                return true;
            }
            catch (Exception)
            {
                trans.Rollback();
                throw;
            }
        }

        public bool ModifyMachineAccounts(MachineAccountData entity)
        {
            var trans = new Transaction(IsolationLevel.ReadCommitted, "ModifyMachineAccounts");
            try
            {
                if (entity.PaymentOrIncome == MachineAccountType.Income)
                {
                    var machineAccountEntity = new MachineAccountIncomeEntity(entity.Id);
                    GetMachineAccountIncomeEntity(machineAccountEntity, entity);
                    trans.Add(machineAccountEntity);
                    machineAccountEntity.Save();
                }
                else if (entity.PaymentOrIncome == MachineAccountType.Payment)
                {
                    var machineAccountEntity = new MachineAccountPaymentEntity(entity.Id);
                    GetMachineAccountPaymentEntity(machineAccountEntity, entity);
                    trans.Add(machineAccountEntity);
                    machineAccountEntity.Save();
                    UpdateGoodsUnloadingCost(trans, entity);
                }

                trans.Commit();

                return true;
            }
            catch (Exception)
            {
                trans.Rollback();
                throw;
            }
        }

        public bool RemoveMachineAccounts(Guid machineAccountId, MachineAccountType type)
        {
            var trans = new Transaction(IsolationLevel.ReadCommitted, "RemoveMachineAccounts");
            try
            {

                if (type == MachineAccountType.Income)
                {
                    var machineAccountEntity = new MachineAccountIncomeEntity(machineAccountId);
                    trans.Add(machineAccountEntity);
                    machineAccountEntity.Delete();

                }
                else if (type == MachineAccountType.Payment)
                {
                    var machineAccountEntity = new MachineAccountPaymentEntity(machineAccountId);
                    trans.Add(machineAccountEntity);
                    machineAccountEntity.Delete();
                }

                trans.Commit();
                return true;
            }
            catch (Exception)
            {
                trans.Rollback();
                throw;
            }
        }

        public MachineAccountData GetMachineAccounts(Guid machineAccountId, MachineAccountType type)
        {

            if (type == MachineAccountType.Income)
            {
                return GetMachineAccountIncomeData(new MachineAccountIncomeEntity(machineAccountId));

            }
            else if (type == MachineAccountType.Payment)
            {
                return GetMachineAccountPaymentData(new MachineAccountPaymentEntity(machineAccountId));
            }
            return null;
        }
        public MachineAccountData GetMachineAccountPaymentSummary(MachineAccountData machineAccountData)
        {
            var service = ServiceContainer.GetService<IIssuingOrderService>();
            var order = service.GetSimpleIssuingOrder(machineAccountData.IssuingOrderId.Value);
            machineAccountData.DueShippingCost = order.ShuntingCost;

            var machineAccounts = new MachineAccountPaymentCollection();
            machineAccounts.GetMulti(MachineAccountPaymentFields.IssuingOrderId ==
                                                           machineAccountData.IssuingOrderId);
            machineAccountData.PaidShippingCost = machineAccounts.Sum(m => m.TobePaidShippingCost);
            machineAccountData.PendingShippingCost = machineAccountData.DueShippingCost -
                                                     machineAccountData.PaidShippingCost;

            machineAccountData.GoodsUnloadingCost = order.GoodsUnloadingCost ?? 0;
            if (machineAccountData.PendingShippingCost < 0)
            {
                machineAccountData.PendingShippingCost = 0;
            }
            return machineAccountData;
        }


        public bool ExistsPaymentMachineAccountByIssuingOrder(Guid issuingOrderId)
        {
            var meta = new LinqMetaData();
            return meta.MachineAccountPayment.Any(a =>
                                                       a.IssuingOrderId == issuingOrderId && a.IsFlag.Value
                 );
        }

        #region private methods

        private bool UpdateGoodsUnloadingCost(Transaction trans, MachineAccountData data)
        {
            if (data.GoodsUnloadingCost > 0)
            {
                var servie = ServiceContainer.GetService<IIssuingOrderService>();
                return servie.UpdateGoodsUnloadingCost(trans, data.IssuingOrderId.Value, data.GoodsUnloadingCost);
            }
            return true;
        }
        private IPredicate GetMachineAccountIncomePredicate(MachineAccountSearchCriteria criteria)
        {
            var expression = new PredicateExpression();

            if (criteria.IssuingOrderId.HasValue)
            {
                expression.Add(MachineAccountIncomeFields.IssuingOrderId == criteria.IssuingOrderId);
            }

            if (criteria.AreaId.HasValue && criteria.AreaId.Value != Guid.Empty)
            {
                expression.Add(MachineAccountIncomeFields.AreaId == criteria.AreaId);
            }
            if (criteria.PaymentOrIncomeDate != null)
            {
                if (criteria.PaymentOrIncomeDate.Start.HasValue)
                {
                    expression.Add(MachineAccountIncomeFields.PaymentOrIncomeDate >= criteria.PaymentOrIncomeDate.Start);
                }
                if (criteria.PaymentOrIncomeDate.End.HasValue)
                {
                    expression.Add(MachineAccountIncomeFields.PaymentOrIncomeDate <= criteria.PaymentOrIncomeDate.End);
                }
            }



            return expression;
        }

        private IPredicate GetMachineAccountPaymentPredicate(MachineAccountSearchCriteria criteria)
        {
            var expression = new PredicateExpression();


            if (criteria.IssuingOrderId.HasValue)
            {
                expression.Add(MachineAccountPaymentFields.IssuingOrderId == criteria.IssuingOrderId);
            }

            if (criteria.AreaId.HasValue && criteria.AreaId.Value != Guid.Empty)
            {
                expression.Add(MachineAccountPaymentFields.AreaId == criteria.AreaId);
            }


            if (criteria.PaymentMethod.HasValue && criteria.PaymentMethod.Value != Guid.Empty)
            {
                expression.Add(MachineAccountPaymentFields.PaymentMethod == criteria.PaymentMethod);
            }

            if (criteria.PaymentOrIncomeDate != null)
            {
                if (criteria.PaymentOrIncomeDate.Start.HasValue)
                {
                    expression.Add(MachineAccountPaymentFields.PaymentOrIncomeDate >= criteria.PaymentOrIncomeDate.Start);
                }
                if (criteria.PaymentOrIncomeDate.End.HasValue)
                {
                    expression.Add(MachineAccountPaymentFields.PaymentOrIncomeDate <= criteria.PaymentOrIncomeDate.End);
                }
            }

            //exclude isFlagged field
            expression.Add(MachineAccountPaymentFields.IsFlag == 0);

            return expression;
        }

        private MachineAccountData GetMachineAccountPaymentData(MachineAccountPaymentEntity machineAccountPaymentEntity)
        {
            var machineAccountData = new MachineAccountData()
                                       {
                                           Id = machineAccountPaymentEntity.Id,
                                           OrderCode = machineAccountPaymentEntity.OrderCode,
                                           AreaId =
                                               machineAccountPaymentEntity.AreaId,
                                           PaymentMethod = machineAccountPaymentEntity.PaymentMethod,
                                           PaymentOrIncomeDate = machineAccountPaymentEntity.PaymentOrIncomeDate,
                                           TransportationPlanCode = machineAccountPaymentEntity.TransportationPlanCode,
                                           IssuingOrderId = machineAccountPaymentEntity.IssuingOrderId,
                                           TobePaidShippingCost = machineAccountPaymentEntity.TobePaidShippingCost,
                                     
                                           OtherAmountFromManufactor = machineAccountPaymentEntity.OtherAmountFromManufactor,
                                           DeductionExceptionsAmount = machineAccountPaymentEntity.DeductionExceptionsAmount,
                                           DeductionExceptionsComments = machineAccountPaymentEntity.DeductionExceptionsComments,
                                           CreateBy = machineAccountPaymentEntity.CreateBy,
                                           CreatedDate = machineAccountPaymentEntity.CreatedDate,
                                           LastUpdatedBy = machineAccountPaymentEntity.LastUpdatedBy,
                                           LastUpdatedDate = machineAccountPaymentEntity.LastUpdatedDate,
                                           RouteTypeId = machineAccountPaymentEntity.IssuingOrder.RouteTypeId,
                                           PaymentOrIncome = MachineAccountType.Payment,
                                           IsFlag = machineAccountPaymentEntity.IsFlag,
                                           UserName = new UserEntity(machineAccountPaymentEntity.LastUpdatedBy).UserName
                                       };

                machineAccountData.GoodsUnloadingCost =
                    machineAccountPaymentEntity.IssuingOrder.GoodsUnloadingCost??0;


                
            return GetMachineAccountPaymentSummary(machineAccountData);
        }


        private MachineAccountPaymentEntity GetMachineAccountPaymentEntity(MachineAccountPaymentEntity machineAccountPaymentEntity, MachineAccountData machineAccountData)
        {

            machineAccountPaymentEntity.OrderCode = machineAccountData.OrderCode;
            machineAccountPaymentEntity.AreaId =
                machineAccountData.AreaId;
            machineAccountPaymentEntity.PaymentMethod = machineAccountData.PaymentMethod;
            machineAccountPaymentEntity.PaymentOrIncomeDate = machineAccountData.PaymentOrIncomeDate;
            machineAccountPaymentEntity.TransportationPlanCode = machineAccountData.TransportationPlanCode;
            machineAccountPaymentEntity.IssuingOrderId = machineAccountData.IssuingOrderId;
            machineAccountPaymentEntity.TobePaidShippingCost = machineAccountData.TobePaidShippingCost;
            machineAccountPaymentEntity.OtherAmountFromManufactor = machineAccountData.OtherAmountFromManufactor;
            machineAccountPaymentEntity.DeductionExceptionsAmount = machineAccountData.DeductionExceptionsAmount;
            machineAccountPaymentEntity.DeductionExceptionsComments = machineAccountData.DeductionExceptionsComments;
            machineAccountPaymentEntity.IsFlag = machineAccountData.IsFlag;
            machineAccountPaymentEntity.CreateBy = machineAccountData.CreateBy.Value;
            machineAccountPaymentEntity.CreatedDate = machineAccountData.CreatedDate.Value;
            machineAccountPaymentEntity.LastUpdatedBy = machineAccountData.LastUpdatedBy.Value;
            machineAccountPaymentEntity.LastUpdatedDate = machineAccountData.LastUpdatedDate.Value;

            return machineAccountPaymentEntity;
        }

        private MachineAccountData GetMachineAccountIncomeData(MachineAccountIncomeEntity machineAccountIncomeEntity)
        {
            var machineAccountData = new MachineAccountData()
            {
                Id = machineAccountIncomeEntity.Id,
                IssuingOrderId = machineAccountIncomeEntity.IssuingOrderId,
                AreaId = machineAccountIncomeEntity.AreaId,
                IncomeType = machineAccountIncomeEntity.IncomeType,
                PaymentOrIncomeDate = machineAccountIncomeEntity.PaymentOrIncomeDate,
                IncomeAmount = machineAccountIncomeEntity.IncomeAmount,
                OtherIncome = machineAccountIncomeEntity.OtherIncome,
                CreateBy = machineAccountIncomeEntity.CreateBy,
                CreatedDate = machineAccountIncomeEntity.CreatedDate,
                LastUpdatedBy = machineAccountIncomeEntity.LastUpdatedBy,
                LastUpdatedDate = machineAccountIncomeEntity.LastUpdatedDate,
                OrderCode = machineAccountIncomeEntity.OrderCode,
           
                PaymentOrIncome = MachineAccountType.Income,
                UserName = new UserEntity(machineAccountIncomeEntity.LastUpdatedBy).UserName
            };

            return machineAccountData;
        }


        private MachineAccountIncomeEntity GetMachineAccountIncomeEntity(MachineAccountIncomeEntity machineAccountPaymentEntity, MachineAccountData machineAccountData)
        {

            machineAccountPaymentEntity.IssuingOrderId = machineAccountData.IssuingOrderId;
            machineAccountPaymentEntity.AreaId =
                machineAccountData.AreaId;

            machineAccountPaymentEntity.PaymentOrIncomeDate = machineAccountData.PaymentOrIncomeDate;
            machineAccountPaymentEntity.IncomeAmount = machineAccountData.IncomeAmount;
            machineAccountPaymentEntity.OtherIncome = machineAccountData.OtherIncome;
            machineAccountPaymentEntity.OrderCode = machineAccountData.OrderCode;
            machineAccountPaymentEntity.IncomeType = machineAccountData.IncomeType;
            machineAccountPaymentEntity.CreateBy = machineAccountData.CreateBy.Value;
            machineAccountPaymentEntity.CreatedDate = machineAccountData.CreatedDate.Value;
            machineAccountPaymentEntity.LastUpdatedBy = machineAccountData.LastUpdatedBy.Value;
            machineAccountPaymentEntity.LastUpdatedDate = machineAccountData.LastUpdatedDate.Value;

            return machineAccountPaymentEntity;
        }
        #endregion
    }
}
